﻿using Microsoft.Win32;
using Scrat.Core.Common;
using Scrat.Core.Pojo;
using Scrat.Core.Server;
using Scrat.Teacher.Forms;
using Scrat.Teacher.Pages;
using Sunny.UI;
using Sunny.UI.Win32;
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;

namespace Scrat.Teacher
{
    public partial class MainForm : UIForm
    {
        private const int MAIN_PAGE_INDEX = 1000;
        private const int SCREEN_BROADCAST_INDEX = 2000;
        private const int STU_DEMONSTRATION_INDEX = 3000;
        private const int FILE_DISTRIBUTION_INDEX = 4000;
        private const int FILE_COLLECTION_INDEX = 5000;

        private UDPMessageServer _udpServer;

        
        private ScreenBroadcastPage _screenBroadcastPage;
        private bool _screenServerStatus = false;

        private MainPage _mainPage;
        private bool _hasDoubleClickStudentInfo = false;

        private StuDemonstrationPage _stuDemonstrationPage;

        private static string _serverIPAddr = "127.0.0.1";
        private static int _localMessagePort = 8899;
        private static int _localScreenShanringPort = 2333;

        private static int _studentMessagePort = 9988;
        private static int _studentScreenSharingPort = 2333;

        public MainForm()
        {
            InitializeComponent();

            // 添加topNavBar的节点
            topNavBar.Nodes.Add("主页面");
            topNavBar.Nodes.Add("屏幕广播");
            topNavBar.Nodes.Add("学生演示");
            topNavBar.Nodes.Add("文件分发");
            topNavBar.Nodes.Add("文件收集");

            // 主页面
            topNavBar.SetNodePageIndex(topNavBar.Nodes[0], MAIN_PAGE_INDEX);
            topNavBar.SetNodeSymbol(topNavBar.Nodes[0], 61461);

            // 屏幕广播
            topNavBar.SetNodePageIndex(topNavBar.Nodes[1], SCREEN_BROADCAST_INDEX);
            topNavBar.SetNodeSymbol(topNavBar.Nodes[1], 362352);

            // 学生演示
            topNavBar.SetNodePageIndex(topNavBar.Nodes[2], STU_DEMONSTRATION_INDEX);
            topNavBar.SetNodeSymbol(topNavBar.Nodes[2], 358597);

            // 文件分发
            topNavBar.SetNodePageIndex(topNavBar.Nodes[3], FILE_DISTRIBUTION_INDEX);
            topNavBar.SetNodeSymbol(topNavBar.Nodes[3], 362836);

            // 文件收集
            topNavBar.SetNodePageIndex(topNavBar.Nodes[4], FILE_COLLECTION_INDEX);
            topNavBar.SetNodeSymbol(topNavBar.Nodes[4], 362829);

            // 设置关联
            topNavBar.TabControl = mainTabControl;
            // 增加页面到main
            _mainPage = new MainPage(this);
            AddPage(_mainPage, MAIN_PAGE_INDEX);
            _screenBroadcastPage = new ScreenBroadcastPage(this);
            AddPage(_screenBroadcastPage, SCREEN_BROADCAST_INDEX);

            _stuDemonstrationPage = new StuDemonstrationPage(this);
            AddPage(_stuDemonstrationPage, STU_DEMONSTRATION_INDEX);

            // AddPage(new FileDistributionPage(), FILE_DISTRIBUTION_INDEX);
            AddPage(new FileCollectionPage(), FILE_COLLECTION_INDEX);

            // 显示默认界面
            topNavBar.SelectedIndex = 0;
           
        }

        

        public delegate void ServerConfigChangedDelegate(string serverIPAddr, int screenShanringPort);
        public event ServerConfigChangedDelegate ServerConfigChangedEvent;
        /// <summary>
        /// 右上角设置按钮 click event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_ExtendBoxClick(object sender, EventArgs e)
        {
            ServerConfig config = new ServerConfig();
            config.SetLocalServerParam(_serverIPAddr, _localMessagePort, _localScreenShanringPort);
            config.SetRemoteServerParam(_studentMessagePort, _studentScreenSharingPort);

            FServerConfig fServerConfig = new FServerConfig(config);

            fServerConfig.Render();
            fServerConfig.ShowDialog();
            if (fServerConfig.IsOK)
            {
                if (_screenServerStatus) 
                {
                    Invoke(new Action(() =>
                    {
                        UINotifier.Show("服务参数配置失败,屏幕共享服务正在运行!",
                               UINotifierType.WARNING, "Warning", false, 3000);
                    }));
                    return; 
                }
                // 修改完成后的服务配置信息
                config = fServerConfig.ServerConfig;

                _serverIPAddr = config.LocalServerAddress;
                _localMessagePort = config.LocalMessagePort;
                _localScreenShanringPort = config.LocalScreenSharingPort;

                _studentMessagePort = config.RemoteMessagePort;
                _studentScreenSharingPort = config.RemoteScreenSharingPort;

                _udpServer.RestartServer(_serverIPAddr, _localMessagePort);

                // 发布屏幕广播endPoint发生改变事件, 主要用于屏幕共享服务的端口设置
                ServerConfigChangedEvent?.Invoke(_serverIPAddr, _localScreenShanringPort);
            }

            fServerConfig.Dispose();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            Console.WriteLine("   ,-,--.    _,.----.                ,---.   ,--.--------.  \r\n ,-.'-  _\\ .' .' -   \\  .-.,.---.  .--.'  \\ /==/,  -   , -\\ \r\n/==/_ ,_.'/==/  ,  ,-' /==/  `   \\ \\==\\-/\\ \\\\==\\.-.  - ,-./ \r\n\\==\\  \\   |==|-   |  .|==|-, .=., |/==/-|_\\ |`--`\\==\\- \\    \r\n \\==\\ -\\  |==|_   `-' \\==|   '='  /\\==\\,   - \\    \\==\\_ \\   \r\n _\\==\\ ,\\ |==|   _  , |==|- ,   .' /==/ -   ,|    |==|- |   \r\n/==/\\/ _ |\\==\\.       /==|_  . ,'./==/-  /\\ - \\   |==|, |   \r\n\\==\\ - , / `-.`.___.-'/==/  /\\ ,  )==\\ _.\\=\\.-'   /==/ -/   \r\n `--`---'             `--`-`--`--' `--`           `--`--`   ");

            try 
            {
                _udpServer = UDPMessageServer.GetInstance();
                _udpServer.DataReceiveEvent += OnDataReceive;
                _udpServer.ServerStartSuccess += OnServerStartSuccess;
                _udpServer.ServerErrorEvent += OnServerError;
                _udpServer.DataSendError += OnDataSendError;
                _udpServer.DataSendSuccess += OnDataSendSuccess;

                _udpServer.Start(_serverIPAddr, _localMessagePort);
                
            } catch (Exception ex)
            {
                Invoke(new Action(() =>
                {
                    UINotifier.Show("聊天室启动失败:" + ex.Message.ToString(),
                           UINotifierType.ERROR, "Error", false, 3000);
                }));
            }
            
            lbChatList.Items.Clear();
        }

        public delegate void RequireStuDemonstrateDelegate(Datagram datagram);
        public event RequireStuDemonstrateDelegate RequireStuDemonstrateEvent;

        private void OnDataSendSuccess(Datagram datagram)
        {
            datagram.Identity = Identity.MySelf;

            switch (datagram.DataGramType)
            {
                case DataGramType.Message:
                    string[] messageByte = FormatDatagram.FormatMessage(datagram);
                    BeginInvoke(new Action(() =>
                    {
                        lbChatList.Items.Add(messageByte[0]);
                        lbChatList.Items.Add(messageByte[1]);
                        lbChatList.TopIndex = lbChatList.Count - 2;
                    }));
                    break;
                case DataGramType.OuterData:
                    string[] outerDataByte = FormatDatagram.FormatMessage(datagram);
                    BeginInvoke(new Action(() =>
                    {
                        lbChatList.Items.Add(outerDataByte[0]);
                        lbChatList.Items.Add(outerDataByte[1]);
                        lbChatList.TopIndex = lbChatList.Count - 2;
                    }));
                    break;
                case DataGramType.RaisHands:
                    // do noting! 教授不举手!
                    break;
                case DataGramType.Online:
                    // 教师不发送上线信息
                    break;
                case DataGramType.Downline:
                    // do nothing!
                    break;
                case DataGramType.RequireStuDemonstrate:
                    // 发送完成请求学生演示信息后, 开始尝试连接
                    datagram.RemotePort = _studentScreenSharingPort;
                    Task.Run(() => 
                    {
                        Task.Delay(1000 * 2);// 延迟两秒
                        RequireStuDemonstrateEvent?.Invoke(datagram);
                    });
                    break;
                case DataGramType.FileInfo:
                    YFileInfo info = (YFileInfo)datagram.Data;

                    // 发送文件,回显到屏幕上
                    BeginInvoke(new Action(() =>
                    {
                        lbChatList.Items.Add("Send File => " + info.Filename);
                        lbChatList.TopIndex = lbChatList.Count - 1;
                    }));
                    // 开启服务
                    TCPFileStreamServer server = TCPFileStreamServer.GetInstance(IPAddress.Parse(_serverIPAddr), 8888);
                    server.Start(File.Open(info.FullName, FileMode.Open));

                    /*Task.Run(() =>
                    {
                        Task.Delay(1000 * 10);
                        server.Stop();
                    });*/
                    break;
                default:
                    Console.WriteLine("OnDataReceive(Datagram datagram) default is executed!");
                    break;
            }
        }

        private void OnDataSendError(string errorMessage)
        {
            Invoke(new Action(() =>
            {
                UINotifier.Show(errorMessage,
                       UINotifierType.ERROR, "Error", false, 3000);
            }));
        }

        private void OnServerStartSuccess()
        {
            Invoke(new Action(() =>
            {
                UINotifier.Show("聊天室启动成功:" + _serverIPAddr + ":" + _localMessagePort,
                       UINotifierType.INFO, "Success", false, 3000);
            }));

        }
        private void OnServerError(string errorMessage)
        {
            Invoke(new Action(() =>
            {
                UINotifier.Show("聊天室启动失败:" + errorMessage,
                       UINotifierType.ERROR, "Error", false, 3000);
            }));
        }


        public delegate void StudentOnlineDelegate(string[] studentInfo);
        public event StudentOnlineDelegate StudentOnlineEvent;

        public delegate void StudentDownlineDelegate(string[] studentInfo);
        public event StudentDownlineDelegate StudentDownlineEvent;

        private void OnDataReceive(Datagram datagram)
        {
            switch (datagram.DataGramType)
            {
                case DataGramType.Message:
                    string[] messageByte = FormatDatagram.FormatMessage(datagram);
                    BeginInvoke(new Action(() =>
                    {
                        lbChatList.Items.Add(messageByte[0]);
                        lbChatList.Items.Add(messageByte[1]);
                        lbChatList.TopIndex = lbChatList.Count - 2;
                    }));
                    break;
                case DataGramType.OuterData:
                    string[] outerDataByte = FormatDatagram.FormatMessage(datagram);
                    BeginInvoke(new Action(() =>
                    {
                        lbChatList.Items.Add(outerDataByte[0]);
                        lbChatList.Items.Add(outerDataByte[1]);
                        lbChatList.TopIndex = lbChatList.Count - 2;
                    }));
                    break;
                case DataGramType.RaisHands:
                    Invoke(new Action(() =>
                    {
                        UINotifier.Show("学生:" + datagram.RemoteIPAddr,
                               UINotifierType.INFO, "您的学生举手啦!", false, 3000);
                    }));
                    break;
                case DataGramType.Online:
                    StudentOnlineEvent?.Invoke(FormatDatagram.FormatOnlineOrDownlineDataGram(datagram));
                    break;
                case DataGramType.Downline:
                    StudentDownlineEvent?.Invoke(FormatDatagram.FormatOnlineOrDownlineDataGram(datagram));
                    break;
                case DataGramType.RequireStuDemonstrate:
                    // do nothing!
                    break;
                case DataGramType.FileInfo:
                    // TODO:// 在这里接收文件...
                    break;
                default:
                    Console.WriteLine("OnDataReceive(Datagram datagram) default is executed!");
                    break;

            }
        }

        private async void btnSendMessage_Click(object sender, EventArgs e)
        {
            if (!_udpServer.RunningStatus)
            {
                ShowWarningTip("服务还未启动,请修改参数重新启动哦~");
                return;
            }
            string strMessage = txtMessageInput.Text.ToString().Trim();
            txtMessageInput.Clear();
            txtMessageInput.Focus();
            if (strMessage.Length <= 0) 
            {
                ShowWarningTip("不可以发送空消息哦!");
                return; 
            }
            byte[] byteMsg = Encoding.UTF8.GetBytes(strMessage);
            Datagram datagram = new Datagram(Identity.Teacher, DataGramType.Message, byteMsg);

            datagram.RemoteIPAddr = IPAddress.Broadcast;
            datagram.RemotePort = _studentMessagePort;

            await _udpServer.SendDataGram(datagram);
                
        }

        private void MainForm_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            _udpServer?.Stop();
        }

        private void btnClearMessageContainer_Click(object sender, EventArgs e)
        {
            lbChatList?.Items.Clear();
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            _screenBroadcastPage.ServerStatusChangedEvent += OnScreenServerStatusChanged;
            _mainPage.StudentDoubleClickEvent += OnRequireStuDemonstration;
        }

        private async void OnRequireStuDemonstration(IPAddress stuIPAddr, int port)
        {
            _hasDoubleClickStudentInfo = true;
            SelectPage(MAIN_PAGE_INDEX);
            topNavBar.SelectedIndex = 2;
            topNavBar.TabControl.SelectedIndex = 2;
            topNavBar.Nodes[2].Text = "暂停演示";
            topNavBar.SetNodeSymbol(topNavBar.Nodes[2], 61517);

            // TODO:// 发送请求学生屏幕演示
            Datagram datagram = new Datagram(Identity.Teacher, DataGramType.RequireStuDemonstrate, null);
            datagram.RemoteIPAddr = stuIPAddr;
            datagram.RemotePort = port;

            await _udpServer.SendDataGram(datagram);
        }

        public delegate void StopStuDemonDelegate();
        public event StopStuDemonDelegate StopStuDemonEvent;
        private async void topNavBar_MenuItemClick(string itemText, int menuIndex, int pageIndex)
        {

            switch (menuIndex)
            {
                case 2:
                    if (!_hasDoubleClickStudentInfo)
                    {
                        ShowWarningDialog("请双击在线学生信息以演示!");
                        SelectPage(MAIN_PAGE_INDEX);
                        topNavBar.SelectedIndex = 0;
                        topNavBar.TabControl.SelectedIndex = 0;
                        return;
                    }

                    if (topNavBar.Nodes[2].Text == "暂停演示")
                    {
                        _hasDoubleClickStudentInfo = false;
                        topNavBar.Nodes[2].Text = "学生演示";
                        topNavBar.SetNodeSymbol(topNavBar.Nodes[2], 358597);
                        StopStuDemonEvent?.Invoke();
                    }

                    break;
                case 3:
                    // 文件分发
                    using (var fileDialog = new System.Windows.Forms.OpenFileDialog())
                    {
                        fileDialog.InitialDirectory = @"C:\";
                        fileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                        fileDialog.FilterIndex = 2;
                        fileDialog.RestoreDirectory = true;

                        if (fileDialog.ShowDialog() == DialogResult.OK)
                        {
                            FileInfo info = new FileInfo(fileDialog.FileName);
                            YFileInfo yFileInfo = new YFileInfo(info.FullName, info.Name,
                                info.Length, info.Extension);

                            Datagram datagram = new Datagram(Identity.Teacher, DataGramType.FileInfo, yFileInfo);
                            datagram.RemoteIPAddr = IPAddress.Broadcast;
                            datagram.RemotePort = _studentMessagePort;

                            await _udpServer.SendDataGram(datagram);
                        }
                    }
                    
                    break;
                default:

                    break;
            }
        }

        private void OnScreenServerStatusChanged(bool serverStatus)
        {
            _screenServerStatus = serverStatus;
        }

        
    }
}
